package com.kasax.ipcbus.utils;

import java.lang.reflect.Method;

public class TypeUtils {
    /**
     * 获取方法签名
     *
     * @param method
     * @return
     */
    public static String getMethodId(Method method) {
        StringBuilder sb = new StringBuilder(method.getName());
        sb.append("(");
        Class<?>[] parameterTypes = method.getParameterTypes();
        sb.append(getMethodParameters(parameterTypes));
        sb.append(")");
        return sb.toString();
    }

    /**
     * 获取方法参数
     *
     * @param classes
     * @return
     */
    private static String getMethodParameters(Class<?>[] classes) {
        StringBuilder sb = new StringBuilder();
        int length = classes.length;
        if (length == 0) {
            return sb.toString();
        }
        sb.append(getClassName(classes[0]));
        for (int i = 1; i < length; ++i) {
            sb.append(",").append(getClassName(classes[i]));
        }
        return sb.toString();
    }

    /**
     * 后面再优化
     *
     * @param clazz
     * @return
     */
    private static String getClassName(Class<?> clazz) {
        if (clazz == Boolean.class) {
            return "boolean";
        } else if (clazz == Byte.class) {
            return "byte";
        } else if (clazz == Character.class) {
            return "char";
        } else if (clazz == Short.class) {
            return "short";
        } else if (clazz == Integer.class) {
            return "int";
        } else if (clazz == Long.class) {
            return "long";
        } else if (clazz == Float.class) {
            return "float";
        } else if (clazz == Double.class) {
            return "double";
        } else if (clazz == Void.class) {
            return "void";
        } else {
            return clazz.getName();
        }
    }

    public static Method getMethodForGettingInstance(Class<?> clazz, String methodName, Class<?>[] paramTypes) {
        Method[] methods = clazz.getMethods();
        if (paramTypes == null) {
            paramTypes = new Class[0];
        }
        Method result = null;
        for (Method method : methods) {
            String tmpName = method.getName();
            if ("getInstance".equals(tmpName)) {
                if (classAssignable(method.getParameterTypes(), paramTypes)) {
                    result = method;
                    break;
                }
            }
        }
        if (result != null) {
            if (result.getReturnType() != clazz) {

            }
            return result;
        }
        return null;
    }

    private static boolean classAssignable(Class<?>[] c1s, Class<?>[] c2s) {
        int c2Len = c2s.length;
        if (c1s.length != c2Len) {
            return false;
        }
        for (int i = 0; i < c2Len; ++i) {
            if (c2s[i] == null) {
                continue;
            }

            if (primitiveMatch(c1s[i], c2s[i])) {
                continue;
            }
            if (!c1s[i].isAssignableFrom(c2s[i])) {
                return false;
            }
        }
        return true;
    }

    private static boolean primitiveMatch(Class<?> class1, Class<?> class2) {
        if (!class1.isPrimitive() && !class2.isPrimitive()) {
            return false;
        } else if (class1 == class2) {
            return true;
        } else if (class1.isPrimitive()) {
            return primitiveMatch(class2, class1);
            //class2 is primitive
            //boolean, byte, char, short, int, long, float, and double void
        } else if (class1 == Boolean.class && class2 == boolean.class) {
            return true;
        } else if (class1 == Byte.class && class2 == byte.class) {
            return true;
        } else if (class1 == Character.class && class2 == char.class) {
            return true;
        } else if (class1 == Short.class && class2 == short.class) {
            return true;
        } else if (class1 == Integer.class && class2 == int.class) {
            return true;
        } else if (class1 == Long.class && class2 == long.class) {
            return true;
        } else if (class1 == Float.class && class2 == float.class) {
            return true;
        } else if (class1 == Double.class && class2 == double.class) {
            return true;
        } else if (class1 == Void.class && class2 == void.class) {
            return true;
        } else {
            return false;
        }
    }


    public static Method getMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
        Method result = null;
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName) && classAssignable(method.getParameterTypes(), parameterTypes)) {
                if (result == null) {
                    result = method;
                } else {

                }
            }
        }
        if (result == null) {
            return result;
        }
        return result;
    }
}
